import serial
import math
from time import sleep
import xlrd
import time
import sys
import winsound
import datetime
from DataConvert.DataConvert import *
from Uart.SerialHelper import *
import logging
import logging.config
from os import path
#config_log='../LogConfig/logger.conf'
from Iec21 import *
import threading

import ctypes
dll = ctypes.windll.LoadLibrary( 'hscom.dll' )

from ctypes import *

##########################创建一个c类型的数组指针###################################################################
class pbuf():
    def __init__(self,size=200):
        self.size=size
        self.pt=pointer((c_char * self.size)())
        memset(self.pt, 0, self.size)
    def addr(self):
        return  byref(self.pt)
    def clr(self):
        memset(self.pt, 0, self.size)
    def set(self):
        memset(self.pt, 255, self.size)
    def __get__(self, instance, owner):
        return self.pt.contents.value
    def v(self,):
        return self.pt.contents.value

#####################################API数据类型定义################################################################

c_Meter_No=c_int		#表位
c_Channel_Flag=c_int	#脉冲采样通道
c_Constant=c_double		#脉冲常数
c_Pulse=c_int			#脉冲校验圈数
c_SModel=c_char_p		#标准表型号，与误差读取有关
c_Dev_Port=c_char		#控制的串口号

c_Phase=c_int			#台体相线类型
c_Rate_Freq=c_double	#频率
c_PhaseSequence=c_int	#相序
c_Revers=c_int			#是否反向
c_IABC=c_char_p			#合相，分相控制
c_MError=c_void_p		#误差
c_SData=c_void_p		#台体返回参数

c_Rated_Volt=c_double   #额定电压，同时用于合相调整的比例基准
c_Rated_Curr=c_double   #额定电流，同时用于合相调整的比例基准
c_Volt=c_double         #直接设置的电压值
c_Curr=c_double			#直接设定的电流值
c_Volt1=c_double		#用于比例调整的基准A电压
c_Volt2=c_double		#用于比例调整的基准B电压
c_Volt3=c_double		#用于比例调整的基准C电压
c_Curr1=c_double		#用于比例调整的基准A电流
c_Curr2=c_double		#用于比例调整的基准C电流
c_Curr3=c_double		#用于比例调整的基准C电流

c_Volt_Per=c_double    	#合相比例，100=100%
c_Curr_Per=c_double    	#合相比例，100=100%
c_Volt_Per1=c_double   	#分相比例，100=100%
c_Volt_Per2=c_double   	#分相比例，100=100%
c_Volt_Per3=c_double   	#分相比例，100=100%
c_Curr_Per1=c_double   	#分相比例，100=100%
c_Curr_Per2=c_double   	#分相比例，100=100%
c_Curr_Per3=c_double   	#分相比例，100=100%

c_Uab=c_double  		#直接角度控制
c_Uac=c_double  		#直接角度控制
c_Ang1=c_double 		#直接角度控制
c_Ang2=c_double 		#直接角度控制
c_Ang3=c_double 		#直接角度控制
c_CosP=c_char_p			#用功率因素调整相位
c_CosAng=c_double		#用角度调整相位


########################################## API 函数框架   #############################################################
# 直接写电压电流大小&角度值，不用比例----------------------------------角度+合相直接值，最方便
dll.Adjust_UI3.argtypes = [c_Phase, c_Rate_Freq, c_PhaseSequence, c_Revers, c_Rated_Volt, c_Rated_Curr, c_IABC,c_CosAng, c_SModel, c_Dev_Port]
# 通过 额定，比例&功率因素  同时调节三相电压电流大小----------------功率因素+合相比例
dll.Adjust_UI.argtypes = [c_Phase, c_Rated_Volt, c_Rated_Curr, c_Rate_Freq, c_PhaseSequence, c_Revers, c_Volt_Per,c_Curr_Per, c_IABC, c_CosP, c_SModel, c_Dev_Port]
# 通过 额定，多比例&功率因素 调节三相不同电压电流大小----------------功率因素+三相比例
dll.Adjust_UI2.argtypes = [c_Phase, c_Rated_Volt, c_Rated_Curr, c_Rate_Freq, c_PhaseSequence, c_Revers, c_Volt_Per1,c_Volt_Per2, c_Volt_Per3, c_Curr_Per1, c_Curr_Per2, c_Curr_Per3, c_IABC, c_CosP, c_SModel,c_Dev_Port]
# 通过 额定，多比例&角度 调节三相不同电压电流大小-------------------角度+三相比例
dll.Adjust_UI4.argtypes = [c_Phase, c_Rated_Volt, c_Rated_Curr, c_Rate_Freq, c_PhaseSequence, c_Revers, c_Volt_Per1,c_Volt_Per2, c_Volt_Per3, c_Curr_Per1, c_Curr_Per2, c_Curr_Per3, c_IABC, c_CosAng, c_SModel,c_Dev_Port]
# 通过 额定，多比例&多角度调节-----------------------------------------最全
dll.Adjust_CUST.argtypes = [c_Phase, c_Rate_Freq, c_Volt1, c_Volt2, c_Volt3, c_Curr1, c_Curr2, c_Curr3, c_Uab, c_Uac,c_Ang1, c_Ang2, c_Ang3, c_SModel, c_Dev_Port]
######################################################################################################################
#误差读取
dll.Set_Pulse_Channel.argtypes=[c_Meter_No,c_Channel_Flag , c_Dev_Port]
dll.Error_Start.argtypes = [c_Meter_No,c_Constant,c_Pulse,c_Dev_Port]
dll.Error_Read.argtypes = [ c_MError,c_Meter_No,c_Dev_Port]
#台体数据读取
dll.StdMeter_Read.argtypes=[c_SData,c_SModel,c_Dev_Port]
"""
API 例子
# 直接写电压电流大小&角度值，不用比例----------------------------------角度+合相直接值，最方便
dll.Adjust_UI3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC, CosAng, SModel, Dev_Port)
# 通过 额定，比例&功率因素  同时调节三相电压电流大小----------------功率因素+合相比例
dll.Adjust_UI(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per, Curr_Per, IABC, CosP,SModel, Dev_Port)
# 通过 额定，多比例&功率因素 调节三相不同电压电流大小----------------功率因素+三相比例
dll.Adjust_UI2(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per1, Volt_Per2, Volt_Per3,Curr_Per1, Curr_Per2, Curr_Per3, IABC, CosP, SModel, Dev_Port)
# 通过 额定，多比例&角度 调节三相不同电压电流大小-------------------角度+三相比例
dll.Adjust_UI4(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per1, Volt_Per2, Volt_Per3,Curr_Per1, Curr_Per2, Curr_Per3, IABC, 150, SModel, Dev_Port)
# 通过 额定，多比例&多角度调节-----------------------------------------最全
dll.Adjust_CUST(_phase_3p4wP, Rated_Freq, Volt1, Volt2, Volt3, Curr1, Curr2, Curr3, Uab, Uac, Ang1, Ang2, Ang3, SModel,Dev_Port)

#误差读取
dll.Set_Pulse_Channel(Meter_No, Channel_Flag, Dev_Port)
dll.Error_Start(Meter_No, Constant, Pulse, Dev_Port)
dll.Error_Read(MError.addr(), Meter_No, Dev_Port)
#台体读取
dll.StdMeter_Read(SData.addr(), SModel, Dev_Port)

"""

###############################一些固定的参数配置，宏定义########################################################
_phase_1P=0#单相
_phase_3p4wP=1
_phase_3p4wQ=2
_phase_1Q=7
_model=c_char_p(b"HY5303C-22")# 这个和误差开始有关系的

_channel_Pall=0#有功+-
_channel_Prev=1#有功-
_channel_Qall=2#无功+-
_channel_Qrev=3#无功-
_channel_Clk=4#时钟
_channel_oth=5#投切
_channel_dmd=6#需量

###################################################################################################################
Dev_Port=1
Phase=_phase_3p4wP				#相线种类
Meter_No=2  					#第几个表位
Constant=1000					#脉冲常数
Pulse=1							#校验圈数

##以下四个个参数不做修改
Channel_Flag=_channel_Pall
SModel=_model# 这个和误差开始有关系的
MError=pbuf(1000)
SData=pbuf(2000)

##########################Adjust_UI##################################################################################

Rated_Freq=Rate_Freq=50
PhaseSequence=0					#0=正相序，	1=逆向序
Revers=0						#0=正向，	1=反向
IABC=c_char_p(b'H')				#负载点合分元 H-合元 A-分 AB-分 B C-分 C

Volt        = 230               #直接控制的电压电流，非比例
Curr        = 15
#比例基数，额定电压电流
Rated_Volt	=230
Rated_Curr	=15
#比例系数
Volt_Per	=100
Curr_Per	=100
Volt_Per1 	=80
Volt_Per2 	=100
Volt_Per3 	=100
Curr_Per1 	=100
Curr_Per2 	=80
Curr_Per3 	=100
#相位设置
CosAng=50
CosP=c_char_p(b"1.0")

##########################Adjust_CUST，可以调节角度####################################################################
Volt1=230
Volt2=220
Volt3=200
Curr1=1
Curr2=2
Curr3=3
Uab=120
Uac=240
Ang1=0
Ang2=60
Ang3=100
#######################################################################################################################

def ErrStart():
    # 切换通道
    dll.Set_Pulse_Channel(Meter_No, Channel_Flag, Dev_Port)
    # 开始读取误差
    dll.Error_Start(Meter_No, Constant, Pulse, Dev_Port)
#脉冲采样通道切换--> 负载点调整-->开始测试误差-->误差读取
def ErrRead():
    #dll.Error_Start(Meter_No, Constant, Pulse, Dev_Port)
    dll.Error_Read(MError.addr(), Meter_No, Dev_Port)
    return MError.v()

# python 字符串对齐 http://www.jb51.net/article/66463.htm
dataIndex = ["UA     ", "UB     ", "UC     ", "IA     ", "IB     ", "IC     ",
             "Ang_UIA", "Ang_UIB", "Ang_UIC", "PA     ", "PB     ", "PC     ",
             "QA     ", "QB     ", "QC     ", "SA     ", "SB     ", "SC     ",
             "PALL   ", "QALL   ", "SALL   ", "HZ     ", "PfA    ", "PfB    ",
             "PfC    ", "PfAll  ", "Ang_UAB", "Ang_UAC", ]
lst = []
dic ={}

def DataRead():

    dll.StdMeter_Read(SData.addr(), SModel, Dev_Port)
    a=SData.v()
    strRead = str(a, encoding="utf8")
    strlist = strRead.split(',')
    global  lst
    global  dic
    lst=[]
    #这个是1wei数组
    # j=0
    # for i in strlist:
    #     lst.append(dataIndex[j])
    #     j=j+1
    #     lst.append(i)
    # return lst
    #这个是2wei的数组


    #print(dataIndex)
    #print(strlist)
    for j in range(int(len(dataIndex))):
        lst.append([dataIndex[j],strlist[j]])

    for j in lst:
        dic[j[0].rstrip()]=j[1]
    #print(dic)


    return lst

def printDataRead(index=0xff,fun=print):
    a=lst
    if(index>=len(dataIndex)):
        for l in a:
            fun(l[0],"=",l[1])
    else :
        fun(a[index], "=", a[index+1])


flag=1

class CCC(object):
    def __init__(self):
        self.ad = dll.Adjust_CUST
        self.ad1=dll.Adjust_UI1
        self.ad2 = dll.Adjust_UI2
        self.ad3 = dll.Adjust_UI3
        self.ad4 = dll.Adjust_UI4
        self.Set_Pulse_Channel =dll.Set_Pulse_Channel
        self.Error_Start = dll.Error_Start
        self.Error_Read = dll.Error_Read
        self.Dll_Port_Close= dll.Dll_Port_Close
        self.flag=0

    def close(self):
        self.Dll_Port_Close()
    def ErrStart(self):
        # 切换通道
        self.Set_Pulse_Channel(Meter_No, Channel_Flag, Dev_Port)
        # 开始读取误差
        self.Error_Start(Meter_No, Constant, Pulse, Dev_Port)

    # 脉冲采样通道切换--> 负载点调整-->开始测试误差-->误差读取
    def ErrRead(self):
        # dll.Error_Start(Meter_No, Constant, Pulse, Dev_Port)
        self.Error_Read(MError.addr(), Meter_No, Dev_Port)
        return MError.v()



    #问题  在于当切换read 的时候强制关闭 导致read 为空，可以先在loop2 前 set1 loop1 read then clr

    def loop1(self):
        self.close()
        a = self.ErrRead()
        while 1:
            if(self.flag==1):
                self.close()
                b=self.ErrRead()
                if(b!=a):
                    print(b)
                    a=b

    def loop2(self):
        Volt = 220
        Curr = 10
        CosAng = 20
        while 1:
            self.close()
            self.ad3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC, CosAng, SModel, Dev_Port)
            print("----------------", CosAng, "-----------------------")
            self.close()
            self.ErrStart()
            self.close()
            self.ErrRead()
            self.flag=1
            CosAng+=20
            sleep(10)
            self.flag=0


def NOP():
    sleep(0.0001)


from Iec21.Iec21 import *


if __name__ == '__main__':
    print("test is Run ")

    import clr
    import sys
    # 导入clr时这个模块最好也一起导入，这样就可以用AddReference方法
    import System


    #u=CCC()
    # t2 = threading.Thread(target=u.loop1, name='change')
    # t1 = threading.Thread(target=u.loop2, name='readout')
    # t1.start()
    # t2.start()


    #角度+合相直接值        dll.Adjust_UI3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC,CosAng, SModel, Dev_Port)
    #功率因素+合相比例      dll.Adjust_UI(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per,Curr_Per, IABC, CosP, SModel, Dev_Port)
    #功率因素+三相比例      dll.Adjust_UI2(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per1,Volt_Per2, Volt_Per3, Curr_Per1, Curr_Per2, Curr_Per3, IABC, CosP, SModel, Dev_Port)
    #角度+三相比例          dll.Adjust_UI4(_phase_3p4wP, Rated_Volt, Rated_Curr, Rate_Freq, PhaseSequence, Revers, Volt_Per1, Volt_Per2,Volt_Per3, Curr_Per1, Curr_Per2, Curr_Per3, IABC, 150, SModel, Dev_Port)
    #最全角度控制           dll.Adjust_CUST(_phase_3p4wP,Rated_Freq,Volt1,Volt2,Volt3,Curr1, Curr2,Curr3,Uab, Uac , Ang1 ,Ang2 , Ang3 ,SModel , Dev_Port)


    Volt=230
    Curr=10
    CosAngLst=[60,120,260,330]

    dataloop=["18110605"]
    timeloop=["010001","020001","030001","040001"]



    ############产生tou电量############################

    iecex = Iec21Com(port='com2', bps_before='300', bps_after="9600", wait=1, ByteSize="7", Parity="E", )

    #power on
    dll.Adjust_UI3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC, CosAngLst[0], SModel, Dev_Port)

    for i in range(4):
        #设置时间到tou 1~4
        iecex.start()
        iecex._WriteObis(_obis='0.9.1',data=timeloop[i])
        iecex._WriteObis(_obis='0.9.2', data=iecex.date(dataloop[0]))
        # 设置角度到象限 1~4
        for j in range(4):
            dll.Adjust_UI3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC, CosAngLst[j], SModel, Dev_Port)
            # hold on 2min
            print("Now Power is =", CosAngLst[j])
            for k in range(2*60):
                sleep(1)
                # ErrStart()
                # ErrRead()
                # DataRead()

    iecex.CloseIec21()
    input("输入 Enter 下I")
    dll.Power_Pause(Dev_Port)
    input("输入 Enter 下U")
    dll.Power_Off(Dev_Port)
    dll.Dll_Port_Close()
    while 1 :
        pass





    c=60+90
    #CosAngLst[i&0x03]
    for i in range(100):

        dll.Power_Pause(Dev_Port)
        print("Now is pause ")
        NOP()
        # input("输入 Enter 切换")
        print("Now is change ")
        c=CosAngLst[i&0x03]
        dll.Adjust_UI3(_phase_3p4wP, Rate_Freq, PhaseSequence, Revers, Volt, Curr, IABC, c, SModel, Dev_Port)
        print("Now Power is =" ,c)
        ErrStart()
        ErrRead()
        DataRead()
        NOP()

        # input("输入 Enter 暂停")


        u = Iec21Com(port='com2', bps_before='300', bps_after="9600", wait=1, ByteSize="7", Parity="E", )
        u.start()
        obislist = ['1.8.0', '2.8.0', '3.8.0', '4.8.0', '5.8.0', '6.8.0', '7.8.0', '8.8.0', '11.8.0']
        for i in range(5):
            print(u.ReadObis(obis=obislist, wait=0.5))
            sleep(2)
        u.CloseIec21()
        # input("输入 Enter 暂停")


        #print("UA     ",dic["UA"])
        # print("PfAll  ", dic["PfAll"])
        # print("PALL   ", dic["PALL"])
        # print("QALL   ", dic["QALL"])
        # print("SALL   ", dic["SALL"])


        # sleep(10)


    ################################################################
    #ErrStart()
    #ErrRead()
    #printDataRead()
    # input("输入 Enter 下I")
    # dll.Power_Pause(Dev_Port)
    # input("输入 Enter 下U")
    # dll.Power_Off(Dev_Port)
    # dll.Dll_Port_Close()
